/** @brief Fichier déclarant une classe de gestion de balise XML.
 *
 * Ce fichier contient la déclaration d'une classe permettant de gérer des balises XML.
 *
 * @file ElementDOM.hpp
 * @author Johan "Solo" Luisier
 * @date Septembre 2009
 */
#ifndef ELEMENTDOM_H
#define ELEMENTDOM_H

#include "Utils/debugstreams.hpp"

#include <map>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

/** @brief Class gérant les balises XML.
 *
 * Classe qui permet de gérer les différentes balises d'un fichier XML. Un
 * ElementDOM stocke le nom de la balise, la valeur du champ (si applicable) et
 * les éventuels attributs et leur valeur.
 *
 * Chaque ElementDOM possède en plus un numéro (permet de reconstruire la
 * structure du fhichier source) et un parent (qui est le numéro de l'ElementDO
 * parent). Le "niveau " de l'élément est également stocké (dans l'arbre DOM du
 * fichier).
 *
 * La classe possède un niveau de sortie interne, que l'on peut régler par la
 * ligne ElementDOM::interne du fichier CONFIG.
 *
 * @author Johan "Solo" Luisier
 * @date Septembre 2009
 */
class ElementDOM
{
public:
    /** @brief Constructeur par défaut.
     *
     * Le constructeur par défaut permet également de déterminer tous les champs
     * sauf les attributs de l'ElementDOM.
     *
     * @param[in] bal nom de la balise (tag).
     * @param[in] niv est le niveau dans l'arbre DOM.
     * @param[in] data est la valeur du champ de données.
     * @param[in] numero est le numéro de l'ElementDOm au sein du document lu.
     * @param[in] parent numéro du parent.
     * @param[in] aDonnees @c true si la balise contient des données, @e false sinon.
     */
    ElementDOM(const string& bal = "", const unsigned int& niv = 0,
               const string& data = "", const unsigned int& numero = 0,
               const ElementDOM* parent = 0, const bool& aDonnees = false );
    /**
     * Construteur de copie, effectue un copie profonde.
     *
     * @param[in] dom instance de ElementDOM à copier.
     */
    ElementDOM(const ElementDOM& dom);
    /**
     * Aucune allocation dynamique effectuée dans cette classe, rien à faire
     * ici.
     */
    virtual ~ElementDOM();
    /**
     * Permet de fixer le nom de la balise
     *
     * @param[in] bal nom de la balise
     */
    void setBalise(const string& bal);
    /**
     * Permet de fixer le niveau de l'ElementDOM
     *
     * @param[in] lvl niveau de l'ElementDOM
     */
    void setNiveau(const unsigned int& niv);
    /**
     * Permet de fixer la valeur du champ de données
     *
     * @param[in] data valeur du champ de données
     */
    void setDonnees(const string& data );
    /**
     * Permet de fixer le numéro
     *
     * @param[in] numero numéro de l'ElementDOM
     */
    void setNumero(const unsigned int& numero);
    /**
     * Permet de fixer le parent
     *
     * @param[in] parent parent de l'ElementDOM.
     */
    void setParent(const ElementDOM*& parent);
    /**
     * Permet d'ajouter un enfant à la liste.
     *
     * Une fois l'ajout effectué, on contrôle que chaque enfant n'est
     * présent qu'une fois.
     *
     * @param[in] enfant enfant à ajouter.
     */
    void ajoutEnfant(/*const*/ ElementDOM*& enfant);
    /**
     * Permet de changer la valeur du booléen qui gère la présence de
     * données
     *
     * @param[in] aDonnees @c true si oui, @c false dans le cas contraire.
     */
    void setADonnees(const bool& aDonnees);
    /**
     * Permet d'ajouter un attribut ainsi que sa valeur associée à
     * l'ElementDOM.
     *
     * Les niveaux de sorties suivant permettent d'afficher les informations :
     *    - FUNC début et fin de méthode
     *    - DEBUG récapitulation de l'élément ajouté
     *
     * @param[in] attrib nom de l'attribut
     * @param[in] val valeur de cet attribut
     */
    void ajoutAttribut(const string& attrib, const string& val);
    /**
     * Permet de récupérer le nom de la balise
     *
     * @return nom de la balise (tag)
     */
    const string& balise() const;
    /**
     * Permet de récupérer le niveau
     *
     * @return niveau
     */
    const unsigned int& niveau() const;
    /**
     * Permet de récupérer la valeur du champ de données
     *
     * @return champ de données
     */
    const string& donnees() const;
    /**
     * Permet de récupérer le numéro
     *
     * @return numero
     */
    const unsigned int& numero() const;
    /**
     * Permet de récupérer le parent
     *
     * @return parent
     */
    const ElementDOM* parent() const;
    /**
     * Permet de récupérer la liste des enfants
     *
     * @return pointeur sur le conteneur des parents.
     */
    const vector< const ElementDOM* >* enfants() const;
    /**
     * Permet de savoir si le champ contien des données ou pas
     *
     * @retval true si contient des données, @retval false sinon.
     */
    const bool& aDonnees() const;
    /**
     * Permet de savoir si l'ElementDOM a des attributs
     *
     * @return \e true si oui, \e false sinon
     */
    bool aAttributs() const;
    /**
     * Permet de récupérer le nom de tous les attibuts de l'ElementDOM
     *
     * @return vecteur contenant les noms des attributs
     *
     * @return niveau
     */
    vector< string > attributs() const;
    /**
     * Permet de récupérer la valeur d'un attibut
     *
     * @param[in] attrib nom de l'attribut dont on veut conaître la valeur
     *
     * @return valeur de cet attribut
     */
    const string& attribut(const string& attrib) const;
    /**
     * Permet de récupérer la valeur d'un attribut
     *
     * @param[in] num numéro de l'attribut désiré
     *
     * @return valeur de cet attribut
     */
    const string& attribut(const unsigned int& num) const;
    /**
     * Opérateur d'affectation, effectue la copie profonde.
     *
     * @param[in] dom ElementDOM à copier
     *
     * @return référence sur l'instance courante, pour pouvoir effecturer A = b
     * = c.
     */
    ElementDOM& operator=(const ElementDOM& dom);
    /**
     * Permet d'afficher le nom de l'élément, sa valeur ainsi que ses
     * éventuels asstributs.
     *
     * @param[in] os flot de sortie
     *
     * @return référence sur le flot utilisé, pour pouvoir réutiliser le
     * flot sans problème
    */
    ostream& afficheAttributs(ostream& os) const;
    /**
     * Permet de régler le niveau de sortie de la classe.
     *
     * @param[in] lvl niveau de sortie
     */
    static void setLevel(const DebugLevelType& lvl);
protected:
    /**
     * Nom de la balise, le "tag".
     */
    string Balise;
    /**
     * Niveau hiérarchique de la balise, le document a le niveau 0, et
     * on incrémente en fonction du nombre de parent.
     */
    unsigned int Niveau;
    /**
     * Champ de données de la balise, sous forme de string quel que soit
     * le type réel.
     */
    string Donnees;
    /**
     * Numéro de la balise, permet de réécrire le fichier.
     */
    unsigned int Numero;
    /**
     * Pointeur sur la balise parente.
     */
    const ElementDOM* Parent;
    /**
     * Conteneur de pointeurs sur les enfants
     */
    vector< const ElementDOM* > Enfants;
    /**
     * Booléen permettant de savoir si la balise contient des données ou
     * juste des enfants.
     */
    bool contientDonnees;
    /**
     * Permet de gérer les différents attributs que peut avoir la
     * balise, pour chaque attribut, on a ici une paire nom => valeur.
     */
    map< string, string > Attributs;
private:
    /**
     * Chaîne de caractère vide, utilisée pour le retour d'une chaîne
     * vide.
     */
    static const string null;
    /**
     * Nombre d'attributs.
     */
    unsigned int nbrAttributs;
    /**
     * Niveau de sortie des méthodes de ElementDOM.
     */
    static DebugLevelType interne;
};

#endif // ELEMENTDOM_H
